package com.elong.qadev.run;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.log4j.Logger;

import com.elong.qadev.entity.Entities;
import com.elong.qadev.entity.Header;
import com.elong.qadev.entity.HttpCase;
import com.elong.qadev.entity.NameValuePair;
import com.elong.qadev.entity.RunAfter;
import com.elong.qadev.entity.RunBefore;
import com.elong.qadev.entity.UrlParam;
import com.elong.qadev.tool.HttpClient;
import com.elong.qadev.tool.LoggerUtils;
import com.elong.qadev.tool.StringUtils;

/**
 * 
 * @ClassName: RunClient
 * @Description: TODO(HTTP请求抽象步骤定义)
 * @author kangchen
 * @date 2015年9月1日
 *
 */
public class RunClient {
	Logger logger = Logger.getLogger(RunClient.class);
	protected Map<String, String> content;
	protected String response;
	protected HttpClient httpClient;
	protected Map<String, Object> source;
	protected String strLog;
	protected String request;
	protected boolean isExpected;
	protected int caseId;

	public int getCaseId() {
		return caseId;
	}

	public void setCaseId(int caseId) {
		this.caseId = caseId;
	}

	public String getRequest() {
		return request;
	}

	public void setRequest(String request) {
		this.request = request;
	}

	public boolean isExpected() {
		return isExpected;
	}

	public void setExpected(boolean isExpected) {
		this.isExpected = isExpected;
	}

	public RunClient(Map<String, Object> source) {
		this.source = source;
		this.httpClient = new HttpClient();
		this.content = new HashMap<String, String>();
		this.isExpected = true;
		this.strLog = "";
	}

	public String getStrLog() {
		return strLog;
	}

	public void setStrLog(String strLog) {
		this.strLog = strLog;
	}

	public Map<String, String> getContent() {
		return content;
	}

	public void setContent(Map<String, String> content) {
		this.content = content;
	}

	public HttpClient getHttpClient() {
		return httpClient;
	}

	public void setHttpClient(HttpClient httpClient) {
		this.httpClient = httpClient;
	}

	public Map<String, Object> getSource() {
		return source;
	}

	public void setSource(Map<String, Object> source) {
		this.source = source;
	}

	@Override
	public String toString() {
		return "RunClient [logger=" + logger + ", content=" + content
				+ ", response=" + response + ", httpClient=" + httpClient
				+ ", source=" + source + ", strLog=" + strLog + ", request="
				+ request + "]";
	}

	public String getResponse() {
		return response;
	}

	public void setResponse(String response) {
		this.response = response;
	}

	/* 定义启动运行前置条件 */
	public void runBefore() throws Exception {
		logger.debug("运行前清除上下文环境变量");
		this.content.clear();
	}

	@SuppressWarnings("unchecked")
	public void beforeCase() throws Exception {
		ArrayList<RunBefore> runBefores = (ArrayList<RunBefore>) source
				.get("runBefores");
		execute(runBefores);
		logger.debug("前置条件执行完毕，遍历content-----------------------------------------------------------");
		for (String key : content.keySet()) {
			logger.debug("key:" + key);
			logger.debug("value:" + content.get(key).toString());
		}
		logger.debug("前置条件执行完毕，遍历content------------------------------------------------------------");
	}
	/**
	 * 
	* @Title: execute
	* @Description: TODO(根据传参反射调用执行前置条件)
	* @param @param runAfters
	* @param @return
	* @param @throws Exception    参数
	* @return boolean    返回类型
	* @throws
	 */
	@SuppressWarnings("unchecked")
	private void execute(ArrayList<RunBefore> runBefores) throws Exception {
		if (null != runBefores) {
			for (int i = runBefores.size() - 1; i >= 0; i--) {
				RunBefore runBefore = runBefores.get(i);
				strLog+=LoggerUtils.log("执行前置分类 - "+runBefore.getClassPath()+" - 的方法【"+runBefore.getBeforeMethod()+"】");
				strLog+=LoggerUtils.log("传入参数 - ("+runBefore.getBeforeMethodArgs()+")");
				String className = "com.elong.qadev.self.BeforeMethod";
				logger.debug("className:" + className);
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				Class<?> setUpClass = cl.loadClass(className);
				Constructor<?> setUpConstructor = setUpClass.getConstructor();
				Object runBeforeObject = setUpConstructor.newInstance();
				logger.debug("获取到类名是：" + runBeforeObject.toString());
				Method method_msgClient = runBeforeObject.getClass().getMethod(
						"setContent", Map.class);
				method_msgClient.invoke(runBeforeObject, content);

				String methodName = com.elong.qadev.tool.StringUtils
						.replaceAfterContent(runBefore.getBeforeMethod(),
								content); // 获取方法名
				StringBuilder sb = new StringBuilder();
				sb.append(String.format("【%s】execute %s(", className,
						methodName));
				String[] argumentsA = com.elong.qadev.tool.StringUtils
							.replaceAfterContent(runBefore.getBeforeMethodArgs(),
									content).split(",");
				List<String> arguments=null;
				if(runBefore.getBeforeMethodArgs().length()<=0){
					arguments = Arrays.asList();
				}else{
					arguments = Arrays.asList(argumentsA);
				}
				Object[] args = new String[arguments.size()];
				for (int j = 0; j < args.length; ++j) {
					if (0 != j) {
						sb.append(", ");
					}
					args[j] = com.elong.qadev.tool.StringUtils
							.replaceAfterContent(arguments.get(j).toString(), content);
					sb.append(args[j]);
				}
				sb.append(")");
				logger.info(sb.toString());
				Class<?>[] parameterTypes = new Class<?>[args.length];
				for (int j = 0; j < args.length; ++j) {
					parameterTypes[j] = args[j].getClass();
				}
				Method method = runBeforeObject.getClass().getMethod(
						methodName, parameterTypes);
				try {
					Object obj = method.invoke(runBeforeObject, args);
					if (null != obj
							&& obj instanceof Boolean
							&& Boolean.valueOf(obj.toString()).equals(
									Boolean.TRUE)) {
						break;
					}
				} catch (Exception ex) {
					logger.error(String.format("校验失败：%s",
							String.valueOf(ex.getCause())));
					throw new Exception(ex);
				}
				Method method_getContent = runBeforeObject.getClass()
						.getMethod("getContent");
				content = (Map<String, String>) method_getContent
						.invoke(runBeforeObject);
				Method method_getStrLog = runBeforeObject.getClass()
						.getMethod("getStrLog");
				strLog+=method_getStrLog.invoke(runBeforeObject);
			}
		}
	}
	/**
	 * 
	* @Title: assemble
	* @Description: TODO(HTTP请求组装)
	* @param @return
	* @param @throws Exception    参数
	* @return String    返回类型
	* @throws
	 */
	@SuppressWarnings("unchecked")
	public String assemble() throws Exception {
		HttpCase h = (HttpCase) source.get("httpCase");
		caseId = h.getCaseId();
		logger.debug("获取caseId:"+caseId);
		String httpUrl = StringUtils.replaceAfterContent(h.getHttpUrl(),
				content);
		String httpMethod = h.getHttpMethod();
		ArrayList<Header> headers = replaceListWithContent0(
				((ArrayList<Header>) source.get("headers")), content);
		ArrayList<UrlParam> urlParams = replaceListWithContent1(
				((ArrayList<UrlParam>) source.get("urlParams")), content);
		ArrayList<NameValuePair> nameValuePairs = replaceListWithContent2(
				((ArrayList<NameValuePair>) getSource().get("nameValuePairs")),
				content);
		Entities entities = (Entities) source.get("entities");

		if (entities.getData() != null) {
			entities.setData(StringUtils.replaceAfterContent(
					entities.getData(), content));
		}

		logger.debug("组装输入数据是：-------------------------------------------------------------");
		logger.debug("httpCase:" + h.toString());
		if (headers != null)
			logger.debug("headers:" + Arrays.toString(headers.toArray()));
		if (urlParams != null)
			logger.debug("urlParams:" + Arrays.toString(urlParams.toArray()));
		if (nameValuePairs != null)
			logger.debug("nameValuePairs:"
					+ Arrays.toString(nameValuePairs.toArray()));
		logger.debug("entities:" + entities.toString());
		logger.debug("组装输入数据是：-------------------------------------------------------------");

		String request = httpClient.assemble(httpUrl, httpMethod, headers,
				urlParams, entities, nameValuePairs);
		return request;
	}

	public ArrayList<Header> replaceListWithContent0(ArrayList<Header> lh,
			Map<String, String> map) {
		if (map == null) {
			return lh;
		}
		if (lh == null) {
			return lh;
		}
		for (int i = 0; i < lh.size(); i++) {
			Header h = new Header();
			h = lh.get(i);
			h.setValue(StringUtils.replaceAfterContent(h.getValue(), map));
			lh.set(i, h);
		}
		return lh;
	}

	public ArrayList<UrlParam> replaceListWithContent1(ArrayList<UrlParam> lh,
			Map<String, String> map) {
		if (map == null) {
			return lh;
		}
		if (lh == null) {
			return lh;
		}
		for (int i = 0; i < lh.size(); i++) {
			UrlParam h = new UrlParam();
			h = lh.get(i);
			h.setValue(StringUtils.replaceAfterContent(h.getValue(), map));
			lh.set(i, h);
		}
		return lh;
	}

	public ArrayList<NameValuePair> replaceListWithContent2(
			ArrayList<NameValuePair> lh, Map<String, String> map) {
		if (map == null) {
			return lh;
		}
		if (lh == null) {
			return lh;
		}
		for (int i = 0; i < lh.size(); i++) {
			NameValuePair h = new NameValuePair();
			h = lh.get(i);
			h.setValue(StringUtils.replaceAfterContent(h.getValue(), map));
			lh.set(i, h);
		}
		return lh;
	}
	/**
	 * 
	* @Title: run
	* @Description: TODO(HTTP用例基础运行入口)
	* @param @throws Exception    参数
	* @return void    返回类型
	* @throws
	 */
	public void run() throws Exception{		
			
		try {
			logger.info("执行前置条件，进行环境数据准备工作...");
			strLog += LoggerUtils.log("执行前置条件，进行环境数据准备工作...");
			beforeCase();
			logger.info("开始组装要发送的请求...");
			strLog += LoggerUtils.log("开始组装要发送的请求...");
			request = assemble();
			logger.info(String.format("组装后的请求是: %s", request));
			strLog += LoggerUtils.log(String.format("组装后的请求是: %s", request));
			logger.info("开始发送请求...");
			strLog += LoggerUtils.log("开始发送请求...");
			response = send();
			logger.info(String.format("得到的响应长度是: %s", response.length()+""));
			logger.info(String.format("得到的响应是: %s", response));
			strLog += LoggerUtils.log("得到响应...");
			logger.info("执行后置条件，执行验证点...");
			strLog += LoggerUtils.log("执行后置条件，执行验证点...");
		} catch (Exception e) {
			isExpected = false;
			strLog += LoggerUtils.log("运行异常，请仔细检查服务参数，错误原因如下：\n"
					+ String.valueOf(Arrays.toString(e.getStackTrace())));
			throw e;
		}
			afterCase();
			logger.debug("执行后置条件得到验证结果为：" + (isExpected ? "通过" : "失败"));
			strLog += LoggerUtils.log("执行后置条件得到验证结果为："
					+ (isExpected ? "通过" : "失败"));
			
			logger.debug("保存执行结果...");
			strLog+=LoggerUtils.log("保存执行结果...");
			logger.info("执行完毕，关闭客户端...");
			strLog += LoggerUtils.log("执行完毕，关闭客户端...");
			close();
	}

	public String send() throws Exception {
		response = httpClient.send();
		return response;
	}

	@SuppressWarnings("unchecked")
	public void afterCase() throws Exception {
		ArrayList<RunAfter> runAfters = (ArrayList<RunAfter>) source
				.get("runAfters");
		executeAfter(runAfters);
		logger.debug("后置条件执行完毕，遍历content-----------------------------------------------------------");
		for (String key : content.keySet()) {
			logger.debug("key:" + key);
			logger.debug("value:" + content.get(key).toString());
		}
		logger.debug("后置条件执行完毕，遍历content------------------------------------------------------------");
	}
	/**
	 * 
	* @Title: executeAfter
	* @Description: TODO(根据传参反射调用执行后置条件)
	* @param @param runAfters
	* @param @return
	* @param @throws Exception    参数
	* @return boolean    返回类型
	* @throws
	 */
	@SuppressWarnings("unchecked")
	private boolean executeAfter(ArrayList<RunAfter> runAfters)
			throws Exception {
		if (null != runAfters) {
			for (int i = runAfters.size() - 1; i >= 0; i--) {
				RunAfter runAfter = runAfters.get(i);
				strLog+=LoggerUtils.log("执行后置分类 - "+runAfter.getClassPath()+" - 的方法【"+runAfter.getAfterMethod()+"】");
				strLog+=LoggerUtils.log("传入参数 - ("+runAfter.getAfterMethodArgs()+")");
				String className = "com.elong.qadev.self.AfterMethod";
				logger.debug("className:" + className);
				ClassLoader cl = Thread.currentThread().getContextClassLoader();
				Class<?> setUpClass = cl.loadClass(className);
				Constructor<?> setUpConstructor = setUpClass.getConstructor();
				Object runAfterObject = setUpConstructor.newInstance();
				logger.debug("获取到类名是：" + runAfterObject.toString());
				Method method_msgClient = runAfterObject.getClass().getMethod(
						"setContent", Map.class);
				method_msgClient.invoke(runAfterObject, content);
				Method method_response = runAfterObject.getClass().getMethod(
						"setResponse", String.class);
				method_response.invoke(runAfterObject, response);
				String methodName = com.elong.qadev.tool.StringUtils
						.replaceAfterContent(runAfter.getAfterMethod(), content); // 获取方法名
				StringBuilder sb = new StringBuilder();
				sb.append(String.format("【%s】execute %s(", className,
						methodName));
				String[] argumentsB = com.elong.qadev.tool.StringUtils
						.replaceAfterContent(runAfter.getAfterMethodArgs(),
								content).split(",");
				List<String> arguments=null;
				if(runAfter.getAfterMethodArgs().length()<=0){
					arguments = Arrays.asList();
				}else{
					arguments = Arrays.asList(argumentsB);
				}
				Object[] args = new String[arguments.size()];
				for (int j = 0; j < args.length; ++j) {
					if (0 != j) {
						sb.append(", ");
					}
					args[j] = com.elong.qadev.tool.StringUtils
							.replaceAfterContent(arguments.get(j), content);
					sb.append(args[j]);
				}
				sb.append(")");
				logger.info(sb.toString());
				Class<?>[] parameterTypes = new Class<?>[args.length];
				for (int j = 0; j < args.length; ++j) {
					parameterTypes[j] = args[j].getClass();
				}
				Method method = runAfterObject.getClass().getMethod(methodName,
						parameterTypes);
				try {
					Object obj = method.invoke(runAfterObject, args);
					if (null != obj
							&& obj instanceof Boolean
							&& Boolean.valueOf(obj.toString()).equals(
									Boolean.TRUE)) {
						break;
					}
				} catch (Exception ex) {
					isExpected = false;
					strLog+=LoggerUtils.log(String.valueOf(ex.getCause()));
					logger.error(String.format("校验失败：%s",
							String.valueOf(ex.getCause())));
					throw new Exception(ex);
				}
				Method method_getContent = runAfterObject.getClass().getMethod(
						"getContent");
				content = (Map<String, String>) method_getContent
						.invoke(runAfterObject);
			}
		}
		return true;
	}

	public void close() throws Exception {
		httpClient.close();
	};

	/* 定义结束运行后置条件 */
	public void runAfter() throws Exception {

	}
	
	public static void main(String[] args) {

	}

}
